package com.gmrz.webauthn.db.dao;

import com.gmrz.uaf.db.DAOException;
import com.gmrz.util.Strings;
import com.gmrz.util.db.DBUtil;
import com.gmrz.webauthn.protocol.v1.processor.WebAuthnErrorCode;
import com.gmrz.webauthn.protocol.v1.schema.TenantConfig;
import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class BaseTenantConfigDAO extends Dialect implements TenantConfigDAO {

    private static final Logger LOG = LogManager.getLogger(BaseTenantConfigDAO.class);

    private static final String _SQL_SELECT_ALL = "select tc_id,config_cname,config_ename,config_value,data_type,regex,error_msg,createts,tenant_id,trans_type from t_tenant_config where 1 = 1 ";


    private Connection conn_;

    @AssistedInject
    public BaseTenantConfigDAO(@Assisted Connection conn_) {
        this.conn_ = conn_;
    }

    @Override
    public List<TenantConfig> find(TenantConfig tenantConfig) throws DAOException {

        StringBuilder sql = new StringBuilder(_SQL_SELECT_ALL);
        PreparedStatement s = null;
        ResultSet rs = null;
        List<TenantConfig> result = new ArrayList<TenantConfig>();


        try {

            List<Object> paras = null;
            if (tenantConfig != null) {

                paras = new ArrayList<Object>();

                if (StringUtils.isNotBlank(tenantConfig.getTcId())) {
                    sql.append(" and tc_id = ?");
                    paras.add(tenantConfig.getTcId());
                }

                if (StringUtils.isNotBlank(tenantConfig.getConfigCname())) {
                    sql.append(" and config_cname like ?");
                    paras.add(tenantConfig.getConfigCname());
                }

                if (StringUtils.isNotBlank(tenantConfig.getConfigEname())) {
                    sql.append(" and config_ename like ?");
                    paras.add(tenantConfig.getConfigEname());
                }

                if (StringUtils.isNotBlank(tenantConfig.getDataType())) {
                    sql.append(" and data_type = ?");
                    paras.add(tenantConfig.getDataType());
                }

                if (StringUtils.isNotBlank(tenantConfig.getTenantId())) {
                    sql.append(" and tenant_id = ?");
                    paras.add(tenantConfig.getTenantId());
                }

                if (StringUtils.isNotBlank(tenantConfig.getTransType())) {
                    sql.append(" and trans_type = ?");
                    paras.add(tenantConfig.getTransType());
                }
            }

            s = this.conn_.prepareStatement(sql.toString());

            if (paras != null && !paras.isEmpty()) {
                fillStatement(s, paras);
            }
            rs = s.executeQuery();

            while (rs.next()) {
                result.add(readResultSet(rs));
            }
        } catch (SQLException sqle) {
            LOG.error("The following SQL statement failed to execute:\n {}", sql);
            throw new DAOException(WebAuthnErrorCode.ERROR_DATABASE_READ_ERROR, sqle);
        } finally {
            DBUtil.close(rs);
            DBUtil.close(s);
        }

        return result;
    }

    @Override
    public TenantConfig findByConfigENameForWebAuthn(String configName, String tenantId) throws DAOException {
        StringBuilder sql = new StringBuilder(_SQL_SELECT_ALL);
        PreparedStatement s = null;
        ResultSet rs = null;
        TenantConfig tenantConfig = null;


        try {
            if ((!Strings.isNullOrEmpty(configName)) && (!Strings.isNullOrEmpty(tenantId))) {

                sql.append(" and config_ename = ? ");
                sql.append(" and tenant_id = ?");

                List<Object> paras = new ArrayList<Object>();
                paras.add(configName);
                paras.add(tenantId);

                s = this.conn_.prepareStatement(sql.toString());
                fillStatement(s, paras);

                rs = s.executeQuery();

                while (rs.next()) {
                    tenantConfig = readResultSet(rs);
                }
            }
        } catch (SQLException sqle) {
            LOG.error("The following SQL statement failed to execute:\n {}", sql);
            throw new DAOException(WebAuthnErrorCode.ERROR_DATABASE_READ_ERROR, sqle);
        } finally {
            DBUtil.close(rs);
            DBUtil.close(s);
        }

        return tenantConfig;
    }


    private TenantConfig readResultSet(ResultSet rs) throws DAOException {
        TenantConfig tenantConfig = new TenantConfig();
        try {
            int offset = 1;
            tenantConfig.setTcId(rs.getString(offset++));
            tenantConfig.setConfigCname(rs.getString(offset++));
            tenantConfig.setConfigEname(rs.getString(offset++));
            tenantConfig.setConfigValue(rs.getString(offset++));
            tenantConfig.setDataType(rs.getString(offset++));
            tenantConfig.setRegex(rs.getString(offset++));
            tenantConfig.setErrorMsg(rs.getString(offset++));
            tenantConfig.setCreatets(rs.getTimestamp(offset++));
            tenantConfig.setTenantId(rs.getString(offset++));
            tenantConfig.setTransType(rs.getString(offset));

            return tenantConfig;

        } catch (SQLException sqle) {
            LOG.error("Failed to read the Tenant Config Data", sqle);
            throw new DAOException(WebAuthnErrorCode.ERROR_DATABASE_READ_ERROR, sqle);
        }
    }
}
